package reflection;

import org.junit.Test;

import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.Arrays;

/**
 * @author DuJiabao
 * @create 2021-01-11 22:52
 */
public class ReflectionTest {
    @Test
    public void test() throws Exception {
//        通过反射，创建Person类的对象
        Class<Person> personClass = Person.class; // 获取类的类
        Constructor<Person> constructor = personClass.getConstructor(int.class, String.class); // 获取该类的构造器
        Person john = constructor.newInstance(12, "John"); // 实例化对象

//        通过反射获取属性、方法
        Field name = personClass.getDeclaredField("name"); // 获取属性
        System.out.println(john);
        name.set(john, "john"); // 设置对象属性
        System.out.println(john);
        Method toString = personClass.getDeclaredMethod("toString");//获取方法
        System.out.println(toString.invoke(john)); // 调用方法

        // 获取私有的构造器
        Constructor<Person> constructor1 = personClass.getDeclaredConstructor(String.class);
        constructor1.setAccessible(true); //设置成可接触到的
        Person jerry = constructor1.newInstance("jerry");
        System.out.println(jerry);

        // 调用私有属性
        Field age = personClass.getDeclaredField("age");
        age.setAccessible(true);
        age.set(jerry, 20);
        System.out.println(jerry);

        //调用私有方法
        Method setNation = personClass.getDeclaredMethod("setNation", String.class); //形参的类也要传进去
        setNation.setAccessible(true);
        String nation = (String) setNation.invoke(jerry, "中国");
        System.out.println(nation);

//        调用私有的静态方法
        Method staticFunc = personClass.getDeclaredMethod("staticFunc");
        staticFunc.setAccessible(true);
        staticFunc.invoke(Person.class);

        // 获取Class的实例的方法
        // 方法一: .class
        Class<Person> personClass1 = Person.class;
        System.out.println(personClass1);
        //方法二： getClass()
        Person person = new Person();
        Class<? extends Person> personClass2 = person.getClass();
        System.out.println(personClass2);
        //方法三：Class静态方法
        Class<?> personClass3 = Class.forName("reflection.Person");
        System.out.println(personClass3);
        //方法四： ClassLoader
        ClassLoader classLoader = ReflectionTest.class.getClassLoader();
        Class<?> personClass4 = classLoader.loadClass("reflection.Person");
        System.out.println(personClass4);

//        获取运行时类的完整结构
//        获取当前类及父类的public的属性
        Field[] fields = personClass.getFields();
        System.out.println(Arrays.toString(fields));
//        获取当前类的所有属性，无论权限
        Field[] declaredFields = personClass.getDeclaredFields();
        System.out.println(Arrays.toString(declaredFields));
        for (Field declaredField : declaredFields) {
//            获取权限修饰符
            int modifiers = declaredField.getModifiers();
            System.out.print(Modifier.toString(modifiers) + "\t");
//            获取属性类型
            Class<?> type = declaredField.getType();
            System.out.print(type + "\t");
//            获取属性名
            String name1 = declaredField.getName();
            System.out.println(name1);

//          获取当前类及父类的public的方法
            Method[] methods = personClass.getMethods();
            System.out.println(Arrays.toString(methods));
//        获取当前类的所有属性，无论权限
            Method[] declaredMethods = personClass.getDeclaredMethods();
            System.out.println(Arrays.toString(declaredMethods));
            for (Method declaredMethod : declaredMethods) {
//                获取方法的注解
                Annotation[] annotations = declaredMethod.getAnnotations();
                System.out.println(Arrays.toString(annotations));
//              获取返回值类型
                Class<?> returnType = declaredMethod.getReturnType();
                System.out.println(returnType);
//              获取构造器
                Constructor<?>[] constructors = personClass.getConstructors();
                System.out.println(Arrays.toString(constructors));
//              获取父类
                Class<? super Person> superclass = personClass.getSuperclass();
                System.out.println(superclass);
//                获取带泛型的父类
                Type genericSuperclass = personClass.getGenericSuperclass();
                System.out.println(genericSuperclass);
//                获取带泛型的父类的泛型
//                ParameterizedType paramType = (ParameterizedType) genericSuperclass;
//                Type[] actualTypeArguments = paramType.getActualTypeArguments(); //获取泛型列表
            }
        }
    }
}
